package com.yzt.dynamicmodule.activity

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.SurfaceTexture
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.Surface
import android.view.TextureView
import android.view.View
import android.view.View.OnClickListener
import androidx.camera.core.AspectRatio
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.FileOutputOptions
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.camera.video.VideoRecordEvent
import androidx.concurrent.futures.await
import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.baidu.mapapi.search.core.PoiInfo
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureConfig
import com.luck.picture.lib.config.SelectMimeType
import com.yzt.dynamicmodule.R
import com.yzt.dynamicmodule.databinding.ActivityCameraEditBinding
import com.yzt.dynamicmodule.view.CircleProgressButtonView1
import com.yzt.p_base.utils.DisplayUtils
import com.yzt.plugin_imageloader.ImageLoadUtil
import com.yzt.plugin_widget.viewPager.ViewPagerAdapter
import com.yzt.zhuju.activity.BaseViewBindingActivity
import com.yzt.zhuju.arouter.RouterDynamic
import com.yzt.zhuju.network.entity.sysConfig.ReportPhotoBean
import com.yzt.zhuju.utils.BarUtils
import com.yzt.zhuju.utils.GlideImageEngine
import com.yzt.zhuju.utils.McImageCompressEngine
import kotlinx.coroutines.launch
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs

/**
 * 视频录制
 */
@SuppressLint("ClickableViewAccessibility", "MissingPermission")
@Route(path = RouterDynamic.ACTIVITY_GAME_CAMERA)
class CameraEditActivity : BaseViewBindingActivity<ActivityCameraEditBinding>() {

    override fun hideTitleBar() = true

    private var currentPage = 1

    override fun generateViewBinding(): ActivityCameraEditBinding {
        return ActivityCameraEditBinding.inflate(layoutInflater)
    }

    companion object {

        const val DEFAULT_ASPECT_RATIO = AspectRatio.RATIO_16_9

        val TAG: String = CameraEditActivity::class.java.simpleName

        private const val FILENAME = "yyyy-MM-dd-HH-mm-ss"

        private const val VIDEO_EXTENSION = ".mp4"

        fun getOutputDirectory(context: Context): File {
            val appContext = context.applicationContext
            val mediaDir = context.externalMediaDirs.firstOrNull()?.let {
                File(it, appContext.resources.getString(R.string.app_name)).apply { mkdirs() }
            }
            return if (mediaDir != null && mediaDir.exists()) mediaDir else appContext.filesDir
        }

        fun createFile(baseFolder: File, format: String, extension: String) = File(
            baseFolder,
            SimpleDateFormat(format, Locale.US).format(System.currentTimeMillis()) + extension
        )
    }

    private var currentRecording: Recording? = null
    private lateinit var outputDirectory: File
    private lateinit var imageCapture: ImageCapture
    private lateinit var videoCapture: VideoCapture<Recorder>

    private lateinit var recordingState: VideoRecordEvent
    private val mainThreadExecutor by lazy { ContextCompat.getMainExecutor(this) }
    private lateinit var cameraExecutor: ExecutorService
    private var mPlayer = MediaPlayer()

    // 录制的视频地址
    private var localVideoPath: String = ""

    enum class UiState {
        IDLE, RECORDING, FINALIZED
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        BarUtils.setStatusBarLightMode(this, true)
        BarUtils.setStatusBarAlpha(this, 0)
        ARouter.getInstance().inject(this)
        viewBinding.imgBack1.setOnClickListener {
            finish()
        }
        initCameraFragment()
        initTab()
    }

    private fun initTab() {

        val fragments: MutableList<Fragment> = ArrayList()
        val titleList: MutableList<String> = ArrayList()
        fragments.add(TestFragment.getInstance())
        fragments.add(TestFragment.getInstance())
        fragments.add(TestFragment.getInstance())
        titleList.add("视频")
        titleList.add("照片")
        titleList.add("文字")
        viewBinding.viewPager.adapter = ViewPagerAdapter(
            supportFragmentManager, fragments, titleList
        )
        viewBinding.tabLayout.setViewPager(viewBinding.viewPager)
        viewBinding.viewPager.currentItem = currentPage

        // 添加手势滑动监听器
        var startX = 0f
        var startY = 0f
        var deltaX = 0f
        var deltaY = 0f
        viewBinding.container.setOnTouchListener { v, event ->

            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    startX = event.x
                    startY = event.y
                }

                MotionEvent.ACTION_MOVE -> {
                    deltaX = event.x - startX
                    deltaY = event.y - startY
                }

                MotionEvent.ACTION_UP -> {
                    // 处理抬起事件
                    if (abs(deltaX) > abs(deltaY) && deltaX > 5f) {
                        // 右滑操作
                        val currentTabIndex = viewBinding.tabLayout.currentTab
                        if (currentTabIndex < viewBinding.tabLayout.tabCount - 1) {
                            val position = currentTabIndex + 1
                            viewBinding.tabLayout.currentTab = position
                        } else {
                            // 已经到达最后一个标签
                            val intent = Intent(this, DynamicAddTextActivity::class.java)
                            startActivity(intent)
                            finish()
                        }

                    } else if (abs(deltaX) > abs(deltaY) && deltaX < -5f) {
                        // 向左滑动
                        val currentTabIndex = viewBinding.tabLayout.currentTab
                        if (currentTabIndex > 0) {
                            val position = currentTabIndex - 1
                            viewBinding.tabLayout.currentTab = position
                        }
                    }
                }
            }
            true
        }

        viewBinding.viewPager.setOnPageChangeListener(object : OnPageChangeListener {
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {

            }

            override fun onPageSelected(position: Int) {

                if (position == 0) {
                    currentPage = 0
                    viewBinding.btnCamera.visibility = View.GONE
                    viewBinding.btnRecord.visibility = View.VISIBLE
                    resetPage()
                    viewBinding.imgAlbum.visibility = View.GONE
                }

                if (position == 1) {
                    currentPage = 1
                    viewBinding.btnCamera.visibility = View.VISIBLE
                    viewBinding.btnRecord.visibility = View.GONE
                    resetPage()
                    viewBinding.imgAlbum.visibility = View.VISIBLE
                }

                if (position == 2) {
                    val intent = Intent(this@CameraEditActivity, DynamicAddTextActivity::class.java)
                    startActivity(intent)
                    finish()
                }
            }

            override fun onPageScrollStateChanged(state: Int) {

            }
        })
    }

    private suspend fun initVideo() {
        //  初始化采集对象
        val cameraProvider: ProcessCameraProvider = ProcessCameraProvider.getInstance(this).await()
        val preview = Preview.Builder().setTargetAspectRatio(DEFAULT_ASPECT_RATIO).build()
        val surfaceProvider = viewBinding.previewView.surfaceProvider
        preview.setSurfaceProvider(surfaceProvider)
        val recorder = Recorder.Builder()
            .setQualitySelector(QualitySelector.from(Quality.HIGHEST))
            .build()
        videoCapture = VideoCapture.withOutput(recorder)
        imageCapture = ImageCapture.Builder().build()
        try {
            cameraProvider.unbindAll()
            cameraProvider.bindToLifecycle(
                this, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture
            )
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
            resetUIandState("bindToLifecycle failed: $exc")
        }
    }

    /**
     * 录制完成的释放
     */
    private val captureListener = Consumer<VideoRecordEvent> { event ->
        if (event !is VideoRecordEvent.Status) recordingState = event
        updateUI(event)
        if (event is VideoRecordEvent.Finalize) {
            showVideo(event)
        }
    }

    private fun initCameraFragment() {
        outputDirectory = getOutputDirectory(this)
        cameraExecutor = Executors.newSingleThreadExecutor()
        initializeUI()
        lifecycleScope.launch {
            initVideo()
        }
    }

    private fun initializeUI() {

        viewBinding.imgBack1.setOnClickListener {
            finish()
        }

        viewBinding.imgAlbum.setOnClickListener {
            PictureSelector.create(this)
                .openGallery(SelectMimeType.ofImage())
                .setImageEngine(GlideImageEngine.instance)
                .setCompressEngine(McImageCompressEngine.instance)
                .setMaxSelectNum(3)
                .isDirectReturnSingle(true)
                .isDisplayCamera(false)
                .isOpenClickSound(false)
                .isFastSlidingSelect(true)
                .isPreviewFullScreenMode(true)
                .isPreviewZoomEffect(true)
                .isPreviewImage(true)
                .isMaxSelectEnabledMask(true)
                .isGif(false)
                .forResult(PictureConfig.CHOOSE_REQUEST)
        }

        // 录制
        viewBinding.btnRecord.setOnClickListener(object :
            CircleProgressButtonView1.OnClickListener1 {
            override fun onStartRecord() {
                startRecording()
            }

            override fun onRecording(time: Long) {

            }

            override fun onEndRecord(time: Long) {
                stopRecording()
            }
        })

        // 拍照
        viewBinding.btnCamera.setOnClickListener(object : OnClickListener {
            override fun onClick(v: View?) {
                startCamera()
            }
        })

        viewBinding.tvSubmit.setOnClickListener {
            if (localVideoPath == "") {
                showToast("地址为空")
                return@setOnClickListener
            }
            RouterDynamic.AddDynamicActivity(localVideoPath, 0)
            finish()
        }

        viewBinding.tvImgNext.setOnClickListener {
            if (localVideoPath == "") {
                showToast("地址为空")
                return@setOnClickListener
            }
            val list: ArrayList<String> = ArrayList()
            list.add(localVideoPath)
            RouterDynamic.AddDynamicActivity(localVideoPath, list, 1)
            //  RouterDynamic.AddDynamicActivity(localVideoPath, 1)
            finish()
        }

        viewBinding.imgReset.setOnClickListener {
            resetPage()
        }
    }

    private fun resetPage() {
        viewBinding.llRecord.visibility = View.VISIBLE
        viewBinding.llSubmit.visibility = View.GONE
        viewBinding.rlVideoViewerBg.visibility = View.GONE
        viewBinding.tvImgNext.visibility = View.GONE
        if (currentPage == 1) {
            viewBinding.imgAlbum.visibility = View.VISIBLE
        } else {
            viewBinding.imgAlbum.visibility = View.GONE
        }
    }

    private fun startCamera() {
        val outFile = createFile(outputDirectory, FILENAME, VIDEO_EXTENSION)
        val outputOptions = ImageCapture.OutputFileOptions.Builder(outFile).build()
        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this),
            object : ImageCapture.OnImageSavedCallback {
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(outFile)
                    Log.d(TAG, "Photo capture succeeded: $savedUri")
                    ImageLoadUtil.loadImg(
                        this@CameraEditActivity,
                        outFile.absolutePath,
                        viewBinding.imgViewer
                    )
                    localVideoPath = outFile.absolutePath
                    viewBinding.rlVideoViewerBg.visibility = View.VISIBLE
                    viewBinding.llRecord.visibility = View.GONE
                    viewBinding.llSubmit.visibility = View.GONE
                    viewBinding.videoViewer.visibility = View.GONE
                    viewBinding.imgViewer.visibility = View.VISIBLE
                    viewBinding.tvImgNext.visibility = View.VISIBLE
                    if (currentPage == 1) {
                        viewBinding.imgAlbum.visibility = View.GONE
                    }
                }

                override fun onError(exc: ImageCaptureException) {
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }
            })
    }

    private fun startRecording() {
        val outFile = createFile(outputDirectory, FILENAME, VIDEO_EXTENSION)
        Log.i(TAG, "outFile: $outFile")
        val outputOptions: FileOutputOptions = FileOutputOptions.Builder(outFile).build()
        currentRecording = videoCapture.output.prepareRecording(this, outputOptions)
            .start(mainThreadExecutor, captureListener)
    }

    private fun stopRecording() {
        currentRecording?.stop()
        currentRecording = null
    }

    private fun updateUI(event: VideoRecordEvent) {
        Log.i(TAG, "event.getName(): ${event.getName()}")
        when (event) {
            is VideoRecordEvent.Status -> {
            }

            is VideoRecordEvent.Start -> {
                showUI(UiState.RECORDING, event.getName())
            }

            is VideoRecordEvent.Finalize -> {
                showUI(UiState.FINALIZED, event.getName())
            }

            is VideoRecordEvent.Pause -> {
            }

            is VideoRecordEvent.Resume -> {
            }

            else -> {
                Log.e(TAG, "Error(Unknown Event) from Recorder")
                return
            }
        }

        val stats = event.recordingStats
        val time = java.util.concurrent.TimeUnit.NANOSECONDS.toSeconds(stats.recordedDurationNanos)
        val text = if (time < 10) "00:0$time" else "00:$time"
        Log.i(TAG, "recording event: $text")
    }

    private fun showUI(state: UiState, status: String = "idle") {
        Log.i(TAG, "showUI: UiState: $status")
        viewBinding.let {
            when (state) {
                UiState.IDLE -> {

                }

                UiState.RECORDING -> {

                }

                UiState.FINALIZED -> {

                }
            }
        }
    }

    private fun resetUIandState(reason: String) {
        showUI(UiState.IDLE, reason)
    }

    private fun showVideo(event: VideoRecordEvent) {
        if (event !is VideoRecordEvent.Finalize)
            return
        lifecycleScope.launch {
            //录制完成后的查看
            viewBinding.rlVideoViewerBg.visibility = View.VISIBLE
            if (currentPage == 1) {
                viewBinding.imgAlbum.visibility = View.VISIBLE
            }else{
                viewBinding.imgAlbum.visibility = View.GONE
            }
            viewBinding.llRecord.visibility = View.GONE
            viewBinding.llSubmit.visibility = View.VISIBLE
            viewBinding.videoViewer.visibility = View.VISIBLE
            viewBinding.imgViewer.visibility = View.GONE
            viewBinding.tvImgNext.visibility = View.GONE
            if (initVideoList) {
                playVideo(event.outputResults.outputUri)
            } else {
                initVideoViewListener(event.outputResults.outputUri)
            }

            val path = event.outputResults.outputUri.toString()
            localVideoPath = if (path.startsWith("file://")) path.substring(7) else path
        }
    }

    private var initVideoList = false

    private fun initVideoViewListener(path: Uri) {
        initVideoList = true
        viewBinding.videoViewer.clipToOutline = true
        viewBinding.videoViewer.layoutParams.height =
            (DisplayUtils.getDisplayPxWidth() / 0.7).toInt()
        viewBinding.videoViewer.surfaceTextureListener = object :
            TextureView.SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
                initPlayer(surface, path)
            }

            override fun onSurfaceTextureSizeChanged(
                surface: SurfaceTexture, width: Int, height: Int
            ) {

            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                return false
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {

            }
        }
    }

    private fun initPlayer(surfaceTexture: SurfaceTexture, path: Uri) {
        try {
            mPlayer.setSurface(Surface(surfaceTexture))
            mPlayer.setDataSource(this, path)
            mPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
            mPlayer.setOnPreparedListener { mPlayer.start() }
            playVideo(path)
        } catch (e: IOException) {
            Log.e(TAG, e.toString())
        }
    }

    private fun playVideo(uri: Uri) {
        try {
            mPlayer.reset()
            mPlayer.setDataSource(this, uri)
            mPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
            mPlayer.isLooping = true
            mPlayer.prepareAsync()
        } catch (e: IOException) {
            Log.e(TAG, e.toString())
        }
    }

    private fun releaseMediaPlayer() {
        if (mPlayer != null) {
            if (mPlayer.isPlaying) {
                mPlayer.stop()
            }
            mPlayer.release()
        }
    }

    override fun onDestroy() {
        cameraExecutor.shutdown()
        releaseMediaPlayer()
        super.onDestroy()
    }

    private fun VideoRecordEvent.getName(): String {
        return when (this) {
            is VideoRecordEvent.Status -> "Status"
            is VideoRecordEvent.Start -> "Started"
            is VideoRecordEvent.Finalize -> "Finalized"
            is VideoRecordEvent.Pause -> "Paused"
            is VideoRecordEvent.Resume -> "Resumed"
            else -> "Error(Unknown)"
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_CANCELED) {
            return
        }
        if (requestCode == PictureConfig.CHOOSE_REQUEST) {
            if (data != null) {
                val result = PictureSelector.obtainSelectorList(data)
                val list: ArrayList<String> = ArrayList()
                result.forEach {
                    list.add(it.realPath)
                }
                RouterDynamic.AddDynamicActivity(localVideoPath, list, 1)
                finish()
            }
        }
    }
}